using System;
using System.Web;

using Kannon.Core;
using Kannon.Util;

namespace Kannon.Integration.Iis
{
    public class KannonHttpHandler : IHttpHandler
    {
        private readonly KannonApplication kannonApplication;

        public KannonHttpHandler(Type applicationType)
        {
            kannonApplication = (KannonApplication)Activator.CreateInstance(applicationType);
        }

        public void ProcessRequest(HttpContext context)
        {
            try
            {
                ProcessRequestInternal(context);
            }
            catch(Exception e)
            {
                context.Response.Write(e.ToString());
            }
        }

        public void ProcessRequestInternal(HttpContext context)
        {
            kannonApplication.ApplicationPath = context.Request.ApplicationPath;

            var rackRequest = new KannonRequest {
                HttpMethod = context.Request.HttpMethod,
                Url = new Uri(new Uri(string.Format("{0}://{1}", context.Request.Url.Scheme, context.Request.Url.Authority)),
                    context.Request.Url.AbsolutePath.SubstringAfter(context.Request.ApplicationPath))
            };

            foreach(var header in context.Request.Headers.AllKeys)
                rackRequest.Headers[header] = context.Request.Headers[header];

            var response = kannonApplication.Handle(rackRequest);
            if(response == null) return;

            context.Response.StatusCode = (int)response.StatusCode;

            if(!string.IsNullOrEmpty(response.StatusDescription))
                context.Response.StatusDescription = response.StatusDescription;
            
            SetResponseHeaders(response, context);

            if(response.OutputStream != null)
            {
                var buffer = new byte[1024];
                var bytesRead = response.OutputStream.Read(buffer, 0, 1024);
                do
                {
                    context.Response.OutputStream.Write(buffer, 0, bytesRead);
                    bytesRead = response.OutputStream.Read(buffer, 0, 1024);
                } 
                while(bytesRead > 0);

                response.OutputStream.Dispose();
            } // if

            context.Response.OutputStream.Close();
        }

        private void SetResponseHeaders(KannonResponse response, HttpContext context)
        {
            foreach(var header in response.Headers)
            {
                var name = header.Key;
                var value = response.Headers[name];

                if(string.IsNullOrEmpty(value)) /*continue;//*/throw new ArgumentOutOfRangeException("value", string.Format("null header value for '{0}'", name));
                
                context.Response.Headers[name] = value;
            } // foreach
        }


        public bool IsReusable
        {
            get { return false; }
        }
    }
}